from datetime import datetime
from typing import Annotated

from fastapi import Depends
from sqlalchemy import Integer, and_, func, select

from forward.api.h5.orm.lucky.activity import ActivityORM
from forward.api.h5.orm.lucky.activity_prize import ActivityPrizeORM
from forward.api.h5.orm.lucky.code import CodeORM
from forward.api.h5.orm.lucky.draw import DrawORM
from forward.api.h5.orm.lucky.order import ActivityOrderORM
from forward.api.h5.orm.lucky.prize import PrizeORM
from forward.api.h5.orm.lucky.prize_temp import PrizeTempORM
from forward.api.h5.orm.user import UserORM
from forward.api.h5.schemas.lucky.activity import (
    ActivityDetailOutSchema,
    ActivityListInSchema,
    ActivityPrizeDetailOutSchema,
)
from forward.api.h5.service.lucky.code import CodeService
from forward.api.h5.service.lucky.prize_temp import PrizeTempService
from forward.common.enums import (
    ActivityStatusEnum,
    ActivityTypeEnum,
    CodeStatusEnum,
    PrizeLevelEnum,
)
from forward.dependencies.database import db
from forward.exceptions.base import AppException
from forward.extend.pydantic.result_api import ResultAPI
from forward.http_base import HttpResp
from forward.model.schemas.lucky.prize import PrizeOutSchema
from forward.model.tables.activity import ActivityModel, ActivityOrderModel
from forward.utils.urls import UrlUtil


class ActivityService:
    def __init__(
        self,
        code_service: Annotated[CodeService, Depends()],
        activity_orm: Annotated[ActivityORM, Depends()],
        prize_orm: Annotated[PrizeORM, Depends()],
        draw_orm: Annotated[DrawORM, Depends()],
        user_orm: Annotated[UserORM, Depends()],
        activity_order_orm: Annotated[ActivityOrderORM, Depends()],
        code_orm: Annotated[CodeORM, Depends()],
        prize_temp_orm: Annotated[PrizeTempORM, Depends()],
        activity_prize_orm: Annotated[ActivityPrizeORM, Depends()],
        prize_temp_service: Annotated[PrizeTempService, Depends()],
    ):
        self.code_service = code_service
        self.activit_orm = activity_orm
        self.prize_orm = prize_orm
        self.draw_orm = draw_orm
        self.user_orm = user_orm
        self.activity_order_orm = activity_order_orm
        self.code_orm = code_orm
        self.prize_temp_orm = prize_temp_orm
        self.activity_prize_orm = activity_prize_orm
        self.prize_temp_service = prize_temp_service

    async def lists(self, list_in: ActivityListInSchema):
        where = []
        if list_in.title:
            where.append(ActivityModel.title.like(f"%{list_in.title}%"))
        pagination = await self.activit_orm.lists(
            page_num=list_in.page_num,
            page_size=list_in.page_size,
            where=where,
        )
        lists = []
        for item in pagination.lists:
            data = item.model_dump()
            data["date_limit"] = (
                f"{item.start_time.strftime('%Y-%m-%d')}至{item.end_time.strftime('%Y-%m-%d')}"
            )
            # data["quota_text"] = await self.get_activity_quota_info(item.id)
            # data["status_text"] = ActivityStatusEnum.get_label(item.status)
            lists.append(ActivityDetailOutSchema(**data))
        return ResultAPI(
            data={
                "lists": lists,
                "total": pagination.total,
            }
        )

    async def get_activity_quota_info(self, activity_id: int):
        """
        获取活动剩余抽奖次数
        @param activity_id: 活动id
        @return:
        """
        # 获取活动剩余抽奖次数
        activity_order_count = await self.activity_order_orm.get_count_by_filters(
            activity_id=activity_id
        )
        # 获取活动抽奖码数量
        activity = await self.activit_orm.get_one_by_id(activity_id)
        if not activity:
            raise AppException(exc=HttpResp.FAILED, msg="活动不存在")
        day_limit_num = activity.day_limit_num or 0
        return f"{day_limit_num - activity_order_count}/{day_limit_num}"

    async def detail(self, activity_id: int):
        # 查询活动
        activity = await self.activit_orm.get_one_by_id(activity_id)
        if not activity:
            raise AppException(exc=HttpResp.FAILED, msg="活动不存在")

        # 活动关联的奖品
        activity_prize_list = []
        prizes = await self.activity_prize_orm.get_all_by_filters(
            activity_id=activity.id
        )
        for item in prizes:
            prize = await self.prize_orm.get_one_by_id(item.prize_id)
            if not prize:
                raise AppException(exc=HttpResp.FAILED, msg="奖品不存在")
            prize_dict = prize.model_dump()
            prize_dict["img"] = await UrlUtil.to_absolute_url(prize_dict["img"])
            data = item.model_dump()
            data["prize_level_text"] = PrizeLevelEnum.get_label(item.prize_index)
            data["prize"] = PrizeOutSchema(**prize_dict)
            activity_prize_list.append(ActivityPrizeDetailOutSchema(**data))
        # 活动关联的抽奖模版
        draw = await self.draw_orm.get_one_by_id(activity.draw_id)

        return ResultAPI(
            data={
                "activity": activity,
                "activityPrizeList": activity_prize_list,
                "drawTemplate": draw,
            }
        )

    async def get_draw_num(
        self, activity_id: int, user_id: int, code_: str | None = None
    ):
        """
        获取用户抽奖次数
        @param activity_id: 活动id
        @param user_id: 用户id
        @param code_: 抽奖码
        @return:
        logic：
        1，如果有抽奖码，检测抽奖的状态
        3，返回用户剩余抽奖次数
        """
        # if code_:
        #     code = await self.code_orm.get_one_by_filters(code=code_)
        #     if not code or code.status != CodeStatusEnum.BOUND.value:
        #         return ResultAPI(data={"userDrawResidueCount": 0})
        draw_num = await self.get_user_draw_residue_count(activity_id, user_id)
        return ResultAPI(data={"userDrawResidueCount": draw_num})

    async def get_user_draw_info(
        self, activity_id: int, user_id: int, code_: str | None = None
    ):
        """
        获取用户抽奖信息
        @param activity_id: 活动id
        @param user_id: 用户id
        @param code_: 抽奖码
        @return:

        流程：
        1. 获取活动信息
        2. 获取活动奖品信息
        3. 获取活动抽奖码信息
        4. 获取用户抽奖信息
        5.
        """
        activity = await self.activit_orm.get_one_by_id(activity_id)
        if not activity:
            raise AppException(exc=HttpResp.FAILED, msg="活动不存在")
        activity_type = activity.type
        activity_prize_list = await self.activity_prize_orm.get_all_by_filters(
            activity_id=activity.id
        )
        prize = None
        prize_id = None
        prize_index = None
        prize_temp_id = None
        if activity_type == ActivityTypeEnum.QRCODE.value:

            prize_temp = await self.prize_temp_orm.get_one_by_filters(
                activity_id=activity_id, user_id=user_id, status=0
            )
            if not prize_temp:
                await self.prize_temp_service.gen_prize_temp(activity_id)
            prize_temp = await self.prize_temp_orm.get_one_by_filters(
                activity_id=activity_id, user_id=user_id, status=0
            )
            if not prize_temp:
                raise AppException(exc=HttpResp.FAILED, msg="奖品已抽完")
            prize_id = prize_temp.prize_id
            prize_index = prize_temp.prize_index
            prize_temp_id = prize_temp.id
        elif activity_type == ActivityTypeEnum.GUAGUALE.value:
            if not code_:
                raise AppException(exc=HttpResp.FAILED, msg="抽奖码不能为空")
            code = await self.code_orm.get_one_by_filters(
                code=code_, status=CodeStatusEnum.BOUND.value
            )
            if not code:
                raise AppException(exc=HttpResp.FAILED, msg="抽奖码不存在或已使用")
            prize_index = code.prize_index

        for item in activity_prize_list:
            if item.prize_index == prize_index:
                if item.prize_id is not None:
                    prize = await self.prize_orm.get_one_by_id(item.prize_id)
                    if not prize:
                        raise AppException(exc=HttpResp.FAILED, msg="奖品不存在")
                    prize_dict = prize.model_dump()
                    prize_dict["img"] = await UrlUtil.to_absolute_url(prize_dict["img"])
                    prize = PrizeOutSchema(**prize_dict)
        return ResultAPI(
            data={
                "prizeIndex": prize_index,  # 奖品序号
                "prize": prize,
                "prizeTempId": prize_temp_id,
            }
        )

    # async def get_prize_index_by_qrcode(self, activity_id: int, user_id):
    #     """
    #     获取用户奖品序号
    #     """

    #     prize_temp = await self.prize_temp_orm.get_one_by_filters(activity_id=activity_id, user_id=user_id, status=0)
    #     if not prize_temp_list:
    #         user_activity_prizes = await self.gen_user_activity_prize(activity_id)
    #         for i in user_activity_prizes:
    #             await self.add_user_prize_qrcode(
    #                 activity_id, user_id, i.prize_index, i.prize_id
    #             )
    #     prize_temp = await self.prize_temp_orm.get_one_by_filters(activity_id=activity_id, user_id=user_id, status=0)
    #     if not prize_temp:
    #         return None, None
    #     return prize_temp.id, prize_temp.prize_index

    # async def gen_user_activity_prize(self, activity_id: int):
    #     """
    #     根据活动配置生成奖品
    #     logic:
    #     1. 根据活动奖品数量生成奖品
    #     2. 根据活动奖品数量生成奖品索引
    #     3. 根据活动奖品索引生成奖品
    #     4. 返回奖品
    #     5. 奖品索引和奖品id保存到数据库
    #     6. 返回奖品索引和奖品id
    #     """
    #     # 活动
    #     activity = await self.activit_orm.get_one_by_id(activity_id)
    #     if not activity:
    #         raise AppException(exc=HttpResp.FAILED, msg="活动不存在")
    #     if activity.type != ActivityTypeEnum.QRCODE.value:
    #         raise AppException(exc=HttpResp.FAILED, msg="活动配置错误")
    #     user_limit_num = activity.client_limit_num
    #     # 活动奖品
    #     activity_prize_list = await self.activity_prize_orm.get_all_by_filters(
    #         activity_id=activity_id
    #     )

    #     gen_user_prizes = []
    #     for i in range(user_limit_num):

    #         # 奖池（还有数量的奖品都放进去）随机取出一个作为奖品
    #         prizes_draw: list[ActivityPrizeOutSchema] = []
    #         for item in activity_prize_list:
    #             if item.num and item.num > 0:
    #                 prizes_draw.append(item)
    #         if not prizes_draw:
    #             raise AppException(exc=HttpResp.FAILED, msg="活动奖品已抽完，带添加")
    #         gen_user_prizes.append(random.choice(prizes_draw))

    #     return gen_user_prizes

    # async def add_user_prize_qrcode(
    #     self, activity_id: int, user_id, prize_index: int, prize_id
    # ):
    #     user_prize_qrcode_statement = insert(PrizeTempModel).values(
    #         activity_id=activity_id,
    #         user_id=user_id,
    #         prize_index=prize_index,
    #         prize_id=prize_id,
    #         status=0,
    #     )
    #     res = await db.execute(user_prize_qrcode_statement)
    #     print("add user prize qrcode", res)
    #     return res

    async def get_user_draw_residue_count(self, activity_id: int, user_id: int):
        """
        用户剩余抽奖次数
         1，如果活动今天抽奖次数结束，用户抽奖次数为0。
         2，如果没有结束，再活动限制用户抽奖次数的条件下判断用户今天的抽奖次数）
        """

        # 活动信息
        activity = await self.activit_orm.get_one_by_id(activity_id)
        if not activity:
            raise AppException(exc=HttpResp.FAILED, msg="活动不存在")

        # 活动每日抽奖次数
        activity_everyday_limit_count = (
            activity.day_limit_num if activity.day_limit_num else 0
        )

        # 活动限制用户抽奖次数
        activity_user_everyday_draw_count = (
            activity.client_limit_num if activity.client_limit_num else 0
        )

        # 获取今天的日期范围（从今天00:00:00到23:59:59）
        today_start = datetime.combine(datetime.now().date(), datetime.min.time())
        today_end = datetime.combine(datetime.now().date(), datetime.max.time())
        # 今天活动抽奖次数
        stmt = select(func.count(ActivityOrderModel.id)).where(
            ActivityOrderModel.id == activity_id,
            ActivityOrderModel.created_time >= today_start,
            ActivityOrderModel.created_time <= today_end,
        )

        today_activity_order_count = await db.fetch_val(stmt)

        # 用户在本活动中抽奖次数
        where = []
        where.append(
            func.json_extract(ActivityOrderModel.activity, "$.id").cast(Integer)
            == activity_id
        )
        where.append(
            func.json_extract(ActivityOrderModel.user, "$.id").cast(Integer) == user_id
        )
        activity_orders = await self.activity_order_orm.get_all_by_filters(
            where=and_(*where),
        )
        activity_user_draw_count = len(activity_orders)
        # 用户今天抽奖剩余次数（init）
        today_user_draw_residue_count = activity_user_everyday_draw_count

        # 今天活动抽奖剩余次数
        today_activity_draw_count = (
            (activity_everyday_limit_count - today_activity_order_count)
            if activity_everyday_limit_count != 0
            else 99999
        )
        # 判断今天活动抽奖次数是否结束
        if today_activity_draw_count <= 0:
            today_user_draw_residue_count = 0
            return today_user_draw_residue_count
        # 判断用户今天抽奖次数是否结束
        if activity_user_everyday_draw_count == 0:
            today_user_draw_residue_count = 0
        elif activity_user_everyday_draw_count > 0:
            if activity_user_everyday_draw_count > activity_user_draw_count:
                today_user_draw_residue_count = (
                    activity_user_everyday_draw_count - activity_user_draw_count
                )
            else:
                today_user_draw_residue_count = 0
        return today_user_draw_residue_count

        # async def guaguale_activity_detail(self, code_: str):
        # # 码号
        # code_statement = select(CodeModel).where(CodeModel.code == code_)
        # code_record = await db.fetch_one(code_statement)
        # if not code_record:
        #     raise AppException(exc=HttpResp.FAILED, msg="无效的活动码")
        # code = CodeOutSchema.model_validate(code_record, from_attributes=True)
        # # 号码关联的奖品
        # prize_statement = select(PrizeModel).where(PrizeModel.id == code.prize_id)
        # prize_record = await db.fetch_one(prize_statement)
        # # 奖品关联错误
        # if not prize_record:
        #     raise AppException(exc=HttpResp.FAILED, msg="无效的活动码2")
        # prize = PrizeOutSchema.model_validate(prize_record, from_attributes=True)

        # # 码号实体关联奖品
        # code.prize = prize

        # # 码号关联的活动
        # activity_statement = select(ActivityModel).where(
        #     ActivityModel.id == code.activity_id
        # )
        # activity_record = await db.fetch_one(activity_statement)
        # if not activity_record:
        #     raise AppException(exc=HttpResp.FAILED, msg="无效的活动码3")
        # activity = ActivityOutSchema.model_validate(
        #     activity_record, from_attributes=True
        # )
        # if activity.kefu_img:
        #     activity.kefu_img = get_settings().domain + activity.kefu_img
        # # 活动关联的奖品
        # prizes_statement = (
        #     select(PrizeModel)
        #     .select_from(PrizeModel)
        #     .join(ActivityPrizeModel, ActivityPrizeModel.prize_id == PrizeModel.id)
        #     .join(ActivityModel, ActivityModel.id == ActivityPrizeModel.activity_id)
        #     .where(ActivityPrizeModel.activity_id == activity.id)
        #     .order_by(ActivityPrizeModel.prize_index)
        # )
        # prizes_record = await db.fetch_all(prizes_statement)
        # if not prizes_record:
        #     raise AppException(exc=HttpResp.FAILED, msg="无效的活动码4")
        # prizes = [
        #     PrizeOutSchema.model_validate(prize, from_attributes=True)
        #     for prize in prizes_record
        # ]
        # if not prizes:
        #     raise AppException(exc=HttpResp.FAILED, msg="无效的活动码5")
        # for prize in prizes:
        #     if prize.img:
        #         prize.img = get_settings().domain + prize.img
        # activity.prizes = prizes

        # # # 获取抽奖结果奖品在奖品里面的序号，并绑定到code上面
        # # for index, prize in enumerate(prizes):
        # #     if prize.id == code.prize_id:
        # #         code.prize_index = index
        # # 获取模版
        # draw_statement = select(DrawModel).where(DrawModel.id == activity.draw_id)
        # draw_record = await db.fetch_one(draw_statement)
        # draw = DrawOutSchema.model_validate(draw_record, from_attributes=True)
        # # 查询订单
        # activity_order_statement = select(ActivityOrderModel).where(
        #     ActivityOrderModel.code == code.code
        # )
        # activity_order_record = await db.fetch_one(activity_order_statement)
        # if not activity_order_record:
        #     order = None
        # else:
        #     order = ActivityOrderOutSchema.model_validate(
        #         activity_order_record, from_attributes=True
        #     )
        # # 判断今天活动是否名额已满
        # # 如果今天有抽奖次数，则查询当前抽奖次数 没有测返回0
        # activity_draw_num = -1
        # if activity.is_day_limit_num == 1:
        #     # 查询抽奖次数
        #     activity_day_limit_num = activity.day_limit_num
        #     # 查询活动当前抽奖次数
        #     activit_order_current_draw_num = await db.fetch_val(
        #         select(func.count(ActivityOrderModel.id)).where(
        #             ActivityOrderModel.activity_id == activity.id
        #         )
        #     )
        #     activity_draw_num = activity_day_limit_num - activit_order_current_draw_num

        # return ResultAPI(
        #     data={
        #         "activity": activity,
        #         "code": code,
        #         "draw": draw,
        #         "order": order,
        #         "activitDrawDayNum": activity_draw_num,
        #     }
        # )

        pass

    # async def client_info(self, user_id):
    #     # 查询访客信息
    #     statement = select(ClientModel).where(ClientModel.id == user_id)
    #     record = await db.fetch_one(statement)
    #     if not record:
    #         raise AppException(exc=HttpResp.LOGIN_ACCOUNT_ERROR, msg="")
    #     # client = ClientOutSchema.model_validate(record, from_attributes=True)
    #     client = None
    #     # 查询今天访客抽奖订单数量
    #     # 获取今天的日期范围（从今天00:00:00到23:59:59）
    #     today_start = datetime.combine(
    #         datetime.now().date(), datetime.min.time())
    #     today_end = datetime.combine(
    #         datetime.now().date(), datetime.max.time())

    #     activity_orders_count_statement = (
    #         select(func.count(ActivityOrderModel.id))
    #         .where(ActivityOrderModel.user_id == user_id)
    #         .where(ActivityOrderModel.created_time >= today_start)
    #         .where(ActivityOrderModel.created_time <= today_end)
    #     )
    #     activity_orders_count = await db.fetch_val(activity_orders_count_statement)
    #     today_limit_num = 1
    #     today_draw_num = 0
    #     if activity_orders_count >= today_limit_num:
    #         today_draw_num = 0
    #     else:
    #         today_draw_num = today_limit_num

    #     return ResultAPI(data={"clientId": "client.id", "todayDrawNum": today_draw_num})

    async def check_activity_eligible_(self, activity_id: int):
        activity = await self.activit_orm.get_one_by_id(activity_id)
        if not activity:
            raise AppException(exc=HttpResp.FAILED, msg="活动不存在")
        if activity.start_time and activity.start_time > datetime.now():
            raise AppException(exc=HttpResp.FAILED, msg="活动未开始")
        if activity.end_time and activity.end_time < datetime.now():
            raise AppException(exc=HttpResp.FAILED, msg="活动已结束")
        if activity.lock == 1:
            raise AppException(exc=HttpResp.FAILED, msg="活动已停止")
        # if activity.status == ActivityStatusEnum.END.value:
        #     raise AppException(exc=HttpResp.FAILED, msg="活动已停止")
        # if activity.status == ActivityStatusEnum.WAIT.value:
        #     raise AppException(exc=HttpResp.FAILED, msg="活动未开始")
        # if activity.status == ActivityStatusEnum.CANCELED.value:
        #     raise AppException(exc=HttpResp.FAILED, msg="活动作废")

    async def check_user_eligible_(self, user_id: int, activity_id: int):
        user = await self.user_orm.get_one_by_id(user_id)
        if not user:
            raise AppException(exc=HttpResp.FAILED, msg="用户不存在")
        if user.is_disable == 1:
            raise AppException(exc=HttpResp.FAILED, msg="用户已被禁用")
        draw_residue_count = await self.get_user_draw_residue_count(
            user_id=user_id, activity_id=activity_id
        )
        print("user draw residue count", draw_residue_count)
        if draw_residue_count <= 0:
            raise AppException(exc=HttpResp.FAILED, msg="抽奖次数为0")

    async def check_draw_eligible(
        self,
        user_id: int,
        activity_id: int,
        code: str | None = None,
    ):
        """
        抽奖前检测抽奖是否满足抽奖条件
        条件：
        1，用户：抽奖次数是否满足
        2，code：是否是空码，未被使用等
        3，奖品：是否还有库存
        4，活动：是否开始，结束，下架
        5，商家：
        6，业务员：
        7，客服：
        """
        # 检测用户
        await self.check_user_eligible_(user_id=user_id, activity_id=activity_id)

        # 检测活动
        activity = await self.activit_orm.get_one_by_id(activity_id)

        if not activity:
            raise AppException(exc=HttpResp.FAILED, msg="活动不存在")
        await self.check_activity_eligible_(activity_id)

        if activity.type == ActivityTypeEnum.GUAGUALE.value:
            if not code:
                raise AppException(exc=HttpResp.FAILED, msg="请输入抽奖码")
            # 校验抽奖码状态
            await self.code_service.check_code_status(code)
        elif activity.type == ActivityTypeEnum.QRCODE.value:
            pass
        # 检测抽奖次数
        # data = await self.get_draw_num(activity_id=activity_id, user_id=user_id)

        return ResultAPI()
